import axios, { AxiosInstance } from 'axios'
import { CanceledError } from 'axios'
import { requestAbortController } from './abort'
import { interceptorRequest } from './interceptor-request'
import { interceptorResponse, interceptorResponseError } from './interceptor-response'

type HttpMethod = 'get' | 'post' | 'put' | 'delete' //其他你需要的HTTP方法

//请求包装
function fetchWrapper(axiosInstance: AxiosInstance, method: HttpMethod, config: TFetchConfig) {
  const fetch: TFetchFunction = <Q, P>(request: TRequest<Q>): Promise<TResponse<P>['data']> => {
    let instance: Promise<any> | null = null
    const requestAbort = requestAbortController(method, request)

    const obj = {
      [method === 'get' ? 'params' : 'data']: request.params,
    }

    instance = axiosInstance({
      baseURL: config.baseURL,
      timeout: config.timeout,
      method,
      url: request.url,
      ...obj,
      signal: requestAbort.abort?.signal,
      headers: {
        mock: request.mock,
        mockpath: request.mockPath,
        mockdelay: request.mockDelay,
      },
    })

    return instance
      .then(response => response)
      .catch(err => {
        if (err instanceof CanceledError) {
          throw err
        } else {
          config.showMessage(err?.data?.msg || err.message || err.msg || '请求失败，请稍后再试')
        }
        throw err
      })
      .finally(() => {
        requestAbort.finish()
      })
  }
  return fetch
}

function createFetch<T extends HttpMethod>(
  methods: T[],
  config: TFetchConfig
): Record<T, TFetchFunction> {
  //初始化axios实例
  const axiosInstance = axios.create({
    headers: {
      'Content-Type': 'application/json',
    },
  })

  axiosInstance.interceptors.request.use(interceptorRequest)
  axiosInstance.interceptors.response.use(interceptorResponse, interceptorResponseError)

  if (config.interceptor) {
    config.interceptor.request?.forEach(fn => {
      axiosInstance.interceptors.request.use(fn)
    })
    config.interceptor.response?.forEach(fn => {
      axiosInstance.interceptors.response.use(fn)
    })
  }
  return methods.reduce((res: Record<string, TFetchFunction>, method) => {
    res[method] = fetchWrapper(axiosInstance, method, config)
    return res
  }, {}) as Record<T, TFetchFunction>
}

// //只支持 get，post
// const fetch: Record<'get' | 'post', TFetchFunction> = createFetch(['get', 'post'], {
//   timeout: 1000,
//   baseURL: 'http://localhost:3000',
//   showMessage: () => {},
// })

export default {
  createFetch,
}
